package cn.tqfeiyang.springplus.generator.name;

import cn.tqfeiyang.springplus.generator.jdbc.FieldInfo;
import cn.tqfeiyang.springplus.generator.jdbc.TableInfo;
import cn.tqfeiyang.springplus.generator.util.Pluralizer;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.Getter;
import org.apache.commons.collections.KeyValue;
import org.apache.commons.collections.keyvalue.DefaultKeyValue;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;

/**
 * 命名帮助类
 *
 * @author tqfeiyang
 * @since 2024/10/18 16:57
 */
public class NamingHelper {

    /**
     * 内部被包装的对象
     */
    private Object obj = null;

    /**
     * 内部处理的字符串
     */
    private String str = "";

    /**
     * 私有构造器
     */
    private NamingHelper(Object obj) {
        this.setObj(obj);
    }

    /**
     * 私有构造器
     */
    private NamingHelper(Object obj, String str) {
        this.setObj(obj);
        this.str = str;
    }

    /**
     * 私有构造器
     */
    private NamingHelper(String str) {
        this.str = str;
    }

    /**
     * 设置内部对象
     */
    private void setObj(Object obj) {
        this.obj = obj;
        if (obj instanceof TableInfo) {
            this.str = ((TableInfo) obj).getName();
        } else if (obj instanceof FieldInfo) {
            this.str =  ((FieldInfo) obj).getName();
        } else {
            this.str = "";
        }
    }

    /**
     * 字符串
     */
    public static NamingHelper strValue(String str) {
        return new NamingHelper(str);
    }

    /**
     * 领域名
     */
    public static NamingHelper domainName(TableInfo table) {
        return new NamingHelper(table, parseDomainName(table));
    }

    /**
     * 模块名
     */
    public static NamingHelper moduleName(TableInfo table) {
        return new NamingHelper(table, parseModuleName(table));
    }

    /**
     * Java包名
     */
    public static NamingHelper packageName(TableInfo table) {
        return new NamingHelper(table, parsePackageName(table));
    }

    /**
     * Java类
     */
    public static JavaClassInfo javaClass(TableInfo table, String category, String packageName) {
        return new JavaClassInfo(table, category, packageName, null);
    }

    public static JavaClassInfo javaClass(TableInfo table, String category, String packageName, Consumer<JavaClassInfo> consumer) {
        return new JavaClassInfo(table, category, packageName, consumer);
    }

    /**
     * 静态文件
     */
    public static ResourceFileInfo resourceFile(TableInfo table, String category, String packageName, String extension) {
        return new ResourceFileInfo(table, category, packageName, extension, null);
    }
    public static ResourceFileInfo resourceFile(TableInfo table, String category, String packageName, String extension, Consumer<ResourceFileInfo> consumer) {
        return new ResourceFileInfo(table, category, packageName, extension, consumer);
    }

    /**
     * 键值信息
     */
    public static KeyValueInfo keyValue(String key, String value) {
        return new KeyValueInfo(key, value);
    }

    /**
     * 缓存信息
     */
    public static CacheInfo cache(TableInfo table, String category) {
        return new CacheInfo(table, category);
    }

    /**
     * Swagger接口信息
     */
    public static SwaggerInfo swagger(TableInfo table) {
        return new SwaggerInfo(table);
    }

    /**
     * 小写
     */
    public NamingHelper lower() {
        this.str = this.str.toLowerCase();
        return this;
    }

    /**
     * 大写
     */
    public NamingHelper upper() {
        this.str = this.str.toUpperCase();
        return this;
    }

    /**
     * 字符替换
     */
    public NamingHelper replace(CharSequence target, CharSequence replacement) {
        this.str = this.str.replace(target, replacement);
        return this;
    }

    /**
     * 增加前缀
     */
    public NamingHelper prefix(CharSequence prefix) {
        this.str = prefix + this.str;
        return this;
    }

    /**
     * 增加后缀
     */
    public NamingHelper suffix(CharSequence suffix) {
        this.str = this.str + suffix;
        return this;
    }

    /**
     * 骆驼(Camel)命名，首个单词的首字母小写，之后单词的首字母都大写
     */
    public NamingHelper camel() {
        this.str = NamingStrategy.underlineToCamel(this.str);
        return this;
    }

    /**
     * 帕斯卡(Pascal)命名，所有单词的首字母都大写
     */
    public NamingHelper pascal() {
        this.str = NamingStrategy.capitalFirst(NamingStrategy.underlineToCamel(this.str));
        return this;
    }

    /**
     * 复数
     */
    public NamingHelper plural() {
        this.str = Pluralizer.toPlural(this.str);
        return this;
    }

    /**
     * 下划线
     */
    public NamingHelper underline() {
        this.str = NamingStrategy.camelToUnderline(NamingStrategy.underlineToCamel(this.str));
        return this;
    }

    /**
     * 转成字符串
     *
     * @return 字符串
     */
    @Override
    public String toString() {
        if (StringUtils.isNotBlank(str)) {
            return str;
        } else if (Objects.nonNull(obj)) {
            if (obj instanceof TableInfo) {
                return ((TableInfo) obj).getName();
            } else if (obj instanceof FieldInfo) {
                return ((FieldInfo) obj).getName();
            } else {
                return obj.toString();
            }
        } else {
            return super.toString();
        }
    }


    /**
     * 实体Java类信息
     */
    @Getter
    public static class JavaClassInfo {
        /**
         * 类名
         */
        private String className;

        /**
         * 变量名
         */
        private String variableName;

        /**
         * Java包
         */
        private String javaPackage;

        /**
         * Java导入
         */
        private String javaImport;

        /**
         * Java文件
         */
        private String filePath;

        /**
         * 扩展信息
         */
        private Map<String, Object> extra = new HashMap<>();

        /**
         * 构造方法
         *
         * @param table 数据表
         * @param category 分类，例如服务类 TreeService
         * @param packageName 包名，例如服务包 service
         */
        public JavaClassInfo(TableInfo table, String category, String packageName,
                             Consumer<JavaClassInfo> consumer) {
            this.className = String.format("%s%s",
                    NamingHelper.domainName(table).pascal(),
                    NamingHelper.strValue(category).pascal());
            this.variableName = String.format("%s",
                    NamingHelper.strValue(this.className).camel());
            this.javaPackage = String.format("%s.%s",
                    parsePackageName(table),
                    NamingHelper.strValue(packageName).camel());
            this.javaImport = String.format("%s.%s",
                    this.javaPackage, this.className);
            this.filePath = String.format("src/main/java/%s.java",
                    NamingHelper.strValue(this.javaImport).replace(".", "/"));
            if (consumer != null) {
                consumer.accept(this);
            }
        }
    }

    /**
     * 实体资源文件信息
     */
    @Getter
    public static class ResourceFileInfo {
        /**
         * 文件路径
         */
        private String filePath;

        /**
         * 扩展信息
         */
        private Map<String, Object> extra = new HashMap<>();

        /**
         * 构造方法
         *
         * @param table 数据表
         * @param category 分类，例如映射类 Mapper
         * @param packageName 包名，例如映射包 mapper
         * @param extension 文件后缀
         */
        public ResourceFileInfo(TableInfo table, String category, String packageName, String extension,
                                Consumer<ResourceFileInfo> consumer) {
            String className = NamingHelper.javaClass(table, category, packageName).getClassName();
            this.filePath = String.format("src/main/resources/%s/%s.%s",
                    NamingHelper.moduleName(table).replace(".", "/"),
                    NamingHelper.strValue(className),
                    extension);
            if (consumer != null) {
                consumer.accept(this);
            }
        }
    }


    /**
     * 实体键值信息
     */
    @Getter
    public static class KeyValueInfo {
        /**
         * 类名
         */
        private String key;

        /**
         * 变量名
         */
        private String value;

        /**
         * 构造方法
         */
        public KeyValueInfo(String key, String value) {
            this.key = key;
            this.value = value;
        }
    }

    /**
     * 实体缓存信息
     */
    @Getter
    public static class CacheInfo extends KeyValueInfo {
        /**
         * 构造方法
         *
         * @param table 数据表
         * @param category 分类，例如服务类 TreeCache
         */
        public CacheInfo(TableInfo table, String category) {
            super(
                    String.format("%s_%s",
                            NamingHelper.domainName(table).underline().upper(),
                            NamingHelper.strValue(category).underline().upper()),
                    String.format("%s:%s_%s",
                            NamingHelper.moduleName(table).replace(".", ":"),
                            NamingHelper.domainName(table).underline().lower(),
                            NamingHelper.strValue(category).underline().lower()));
        }
    }


    /**
     * 实体Swagger信息
     */
    @Getter
    public static class SwaggerInfo {
        /**
         * 标签
         */
        private String tag;

        /**
         * 构造方法
         */
        public SwaggerInfo(TableInfo table) {
            this.tag = table.getApifoxFolder();
        }
    }

    /**
     * 获取模块名
     */
    private static String parseModuleName(TableInfo tableInfo) {
        if (StringUtils.isNotBlank(tableInfo.getModuleName())) {
            return tableInfo.getModuleName();
        } else {
            if (StringUtils.isNotBlank(tableInfo.getGeneratorConfig().getModuleName())) {
                return tableInfo.getGeneratorConfig().getModuleName();
            } else if (tableInfo.getGeneratorConfig().isFirstWordAsModuleName()) {
                String tableName = removePrefixAndSuffix(tableInfo);
                String[] parts = tableName.split("_");
                if (parts.length >= 2) {
                    return parts[0];
                } else {
                    return "";
                }
            } else {
                return "";
            }
        }
    }

    /**
     * 获取领域名，例如 GoodsCategory
     */
    private static String parseDomainName(TableInfo tableInfo) {
        String domainName;

        if (StringUtils.isNotBlank(tableInfo.getDomainName())) {
            return tableInfo.getDomainName();
        } else {
            domainName = removePrefixAndSuffix(tableInfo);
            if (tableInfo.getGeneratorConfig().isDomainNameRemoveModulePrefix()) {
                String modulePrefix = moduleName(tableInfo) + "_";
                if (domainName.startsWith(modulePrefix)) {
                    domainName = domainName.substring(modulePrefix.length());
                }
            }
        }

        return NamingStrategy.capitalFirst(NamingStrategy.underlineToCamel(domainName));
    }

    /**
     * 获取Java包名
     */
    private static String parsePackageName(TableInfo tableInfo) {
        String packageName = tableInfo.getGeneratorConfig().getRootPackage();
        if (tableInfo.getGeneratorConfig().isPackageNameWithModule()) {
            String moduleName = parseModuleName(tableInfo);
            if (StringUtils.isNotBlank(moduleName)) {
                packageName = packageName + "." + moduleName;
            }
        }
        if (tableInfo.getGeneratorConfig().isPackageNameWithTable()) {
            String domainName = parseDomainName(tableInfo);
            if (StringUtils.isNotBlank(domainName)) {
                packageName = packageName + "." + NamingStrategy.underlineToCamel(domainName);
            }
        }
        return packageName;
    }

    /**
     * 去掉前缀和后缀
     */
    private static String removePrefixAndSuffix(TableInfo tableInfo) {
        return removePrefixAndSuffix(tableInfo.getName(),
                tableInfo.getGeneratorConfig().getTablePrefix(),
                tableInfo.getGeneratorConfig().getTableSuffix());
    }

    /**
     * 去掉前缀和后缀
     */
    private static String removePrefixAndSuffix(String input, Set<String> prefix, Set<String> suffix) {
        String name = input;
        if (prefix != null) {
            name = NamingStrategy.removePrefix(name, prefix);
        }
        if (suffix != null) {
            name = NamingStrategy.removeSuffix(name, suffix);
        }
        return name;
    }

}
